package lv.solcraft.replication.client.filtering;

import java.util.Date;
import java.util.List;

import javax.sql.DataSource;

import lv.solcraft.replication.common.OperDTO;
import lv.solcraft.replication.common.ReplicationConst;
import lv.solcraft.replication.common.OperDTO.Field;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.rowset.SqlRowSet;

public class OperFilterObject {

    public static String NOT_FOUND_STRING = "<NOT_FOUND>";

    private int siteId;

    private String table;

    private int scrSiteId;

    private int scrRecordId;

    private DataSource dataSource;

    private JdbcTemplate jt;

    private OperDTO oper;

    private String type;

    private Date dateTime;

    public OperFilterObject(DataSource source, OperDTO oper) {
        dataSource = source;
        this.oper = oper;
        jt = new JdbcTemplate(dataSource);
        this.table = oper.getTable();
        this.scrSiteId = oper.getRecordSiteId();
        this.scrRecordId = oper.getRecordId();
        this.siteId = oper.getOperOwnerSiteId();
        this.type = oper.getType();
        this.dateTime = oper.getDateTime();
    }

    public int getScrRecordId() {
        return scrRecordId;
    }

    public int getScrSiteId() {
        return scrSiteId;
    }

    public int getSiteId() {
        return siteId;
    }

    public String getTable() {
        return table;
    }

    public String getType() {
        return type;
    }

    public int getFieldAsInt(String field) {
        SqlRowSet rowSet = getRowSetForField(field);
        if (!rowSet.next()) {
            return Integer.MIN_VALUE;
        }
        return rowSet.getInt(1);
    }

    public long getFieldAsLong(String field) {
        SqlRowSet rowSet = getRowSetForField(field);
        if (!rowSet.next()) {
            return Long.MIN_VALUE;
        }
        return rowSet.getLong(1);
    }

    public String getFieldAsString(String field) {
        SqlRowSet rowSet = getRowSetForField(field);
        if (!rowSet.next()) {
            return NOT_FOUND_STRING;
        }
        return rowSet.getString(1);
    }

    public Date getFieldAsDate(String field) {
        SqlRowSet rowSet = getRowSetForField(field);
        if (!rowSet.next()) {
            return new Date(0);
        }
        return rowSet.getDate(1);
    }

    public double getFieldAsDouble(String field) {
        SqlRowSet rowSet = getRowSetForField(field);
        if (!rowSet.next()) {
            return Double.MIN_VALUE;
        }
        return rowSet.getDouble(1);
    }

    private SqlRowSet getRowSetForField(String field) {

        String sql = "SELECT " + field + " FROM " + table + " WHERE SCR_SITE_ID = ? AND SCR_RECORD_ID = ?";
        SqlRowSet rowSet = jt.queryForRowSet(sql, new Object[] { scrSiteId, scrRecordId });

        return rowSet;
    }

    public int queryForInt(String table, String keyField, String valueField, Object key) {
        SqlRowSet rowSet = getRowSetForQuery(table, keyField, valueField, key);
        if (!rowSet.next()) {
            return Integer.MIN_VALUE;
        }
        return rowSet.getInt(1);
    }

    public long queryForLong(String table, String keyField, String valueField, Object key) {
        SqlRowSet rowSet = getRowSetForQuery(table, keyField, valueField, key);
        if (!rowSet.next()) {
            return Long.MIN_VALUE;
        }
        return rowSet.getLong(1);
    }

    public double queryForDouble(String table, String keyField, String valueField, Object key) {
        SqlRowSet rowSet = getRowSetForQuery(table, keyField, valueField, key);
        if (!rowSet.next()) {
            return Double.MIN_VALUE;
        }
        return rowSet.getDouble(1);
    }

    public String queryForString(String table, String keyField, String valueField, Object key) {
        SqlRowSet rowSet = getRowSetForQuery(table, keyField, valueField, key);
        if (!rowSet.next()) {
            return NOT_FOUND_STRING;
        }
        return rowSet.getString(1);
    }

    public Date queryForDate(String table, String keyField, String valueField, Object key) {
        SqlRowSet rowSet = getRowSetForQuery(table, keyField, valueField, key);
        if (!rowSet.next()) {
            return new Date(0);
        }
        return rowSet.getDate(1);
    }

    private SqlRowSet getRowSetForQuery(String tableName, String keyField, String valueField, Object key) {

        String sql = "SELECT " + valueField + " FROM " + tableName + " WHERE " + keyField + " = ?";
        SqlRowSet rowSet = jt.queryForRowSet(sql, new Object[] { key });

        return rowSet;
    }

    public OperDTO getOper() {
        return oper;
    }

    public void setStateNew(int siteId, String message) {
        oper.setState(siteId, ReplicationConst.STATE_NEW, message);
    }

    public void setStateIgnore(int siteId, String message) {
        oper.setState(siteId, ReplicationConst.STATE_IGNORED, message);
    }

    public void setStateError(int siteId, String message) {
        oper.setState(siteId, ReplicationConst.STATE_ERROR, message);
    }

    public String getFieldValue(String fieldName) {
        Field f = getField(fieldName);
        if (f == null) {
            return NOT_FOUND_STRING;
        } else {
            return f.getValue();
        }
    }

    public void setFieldValue(String fieldName, String value) {
        Field f = getField(fieldName);
        if (f != null) {
            f.setValue(value);
        }
    }

    public void addField(String fieldName, String value) {
        if (existsField(fieldName)) {
            setFieldValue(fieldName, value);
        } else {
            oper.addField(fieldName, value);
        }
    }

    public void removeField(String fieldName) {
        Field f = getField(fieldName);
        if (f != null) {
            oper.getFields().remove(f);
        }
    }

    public boolean existsField(String fieldName) {
        return getField(fieldName) != null;
    }

    private Field getField(String fieldName) {
        for (Field f : oper.getFields()) {
            if (f.getName().equals(fieldName)) {
                return f;
            }
        }
        return null;
    }

    public List<Field> getFields() {
        return oper.getFields();
    }
}
